﻿package com._public._utils{

	/**
	 * 通过新历获取农历
	 * @author wzh(shch8.com)
	 * lunar.setDate()新历设置
	 * lunar.year;获取中国农历年.
	   lunar.yearPro;获取年份
	   lunar.month; 获取中国农历月.
	   lunar.date;获取中国农历日.
	   lunar.dateStr;获取大写农历日格式
	   lunar.monthStr;获取大写农历月格式
	   lunar.nianZhu;获取年柱
	   lunar.yueZhu;获取月柱
	   lunar.riZhu;获取日柱
	   lunar.shiceng;获取时辰
	   lunar.jieQi;获取二十四节气
	   lunar.lunarFeast;获取农历节日
	   lunar.solarFeast;获取新历节日
	   
	 */
	public class Lunar {
		private var txtnum_info:Array = new Array(0x4bd8, 0x4ae0, 0xa570, 0x54d5, 0xd260, 0xd950, 0x5554, 0x56af, 0x9ad0, 0x55d2, 0x4ae0, 0xa5b6, 0xa4d0, 0xd250, 0xd255, 0xb54f, 0xd6a0, 0xada2, 0x95b0, 0x4977, 0x497f, 0xa4b0, 0xb4b5, 0x6a50, 0x6d40, 0xab54, 0x2b6f, 0x9570, 0x52f2, 0x4970, 0x6566, 0xd4a0, 0xea50, 0x6a95, 0x5adf, 0x2b60, 0x86e3, 0x92ef, 0xc8d7, 0xc95f, 0xd4a0, 0xd8a6, 0xb55f, 0x56a0, 0xa5b4, 0x25df, 0x92d0, 0xd2b2, 0xa950, 0xb557, 0x6ca0, 0xb550, 0x5355, 0x4daf, 0xa5b0, 0x4573, 0x52bf, 0xa9a8, 0xe950, 0x6aa0, 0xaea6, 0xab50, 0x4b60, 0xaae4, 0xa570, 0x5260, 0xf263, 0xd950, 0x5b57, 0x56a0, 0x96d0, 0x4dd5, 0x4ad0, 0xa4d0, 0xd4d4, 0xd250, 0xd558, 0xb540, 0xb6a0, 0x95a6, 0x95bf, 0x49b0, 0xa974, 0xa4b0, 0xb27a, 0x6a50, 0x6d40, 0xaf46, 0xab60, 0x9570, 0x4af5, 0x4970, 0x64b0, 0x74a3, 0xea50, 0x6b58, 0x5ac0, 0xab60, 0x96d5, 0x92e0, 0xc960, 0xd954, 0xd4a0, 0xda50, 0x7552, 0x56a0, 0xabb7, 0x25d0, 0x92d0, 0xcab5, 0xa950, 0xb4a0, 0xbaa4, 0xad50, 0x55d9, 0x4ba0, 0xa5b0, 0x5176, 0x52bf, 0xa930, 0x7954, 0x6aa0, 0xad50, 0x5b52, 0x4b60, 0xa6e6, 0xa4e0, 0xd260, 0xea65, 0xd530, 0x5aa0, 0x76a3, 0x96d0, 0x4afb, 0x4ad0, 0xa4d0, 0xd0b6, 0xd25f, 0xd520, 0xdd45, 0xb5a0, 0x56d0, 0x55b2, 0x49b0, 0xa577, 0xa4b0, 0xaa50, 0xb255, 0x6d2f, 0xada0, 0x4b63, 0x937f, 0x49f8, 0x4970, 0x64b0, 0x68a6, 0xea5f, 0x6b20, 0xa6c4, 0xaaef, 0x92e0, 0xd2e3, 0xc960, 0xd557, 0xd4a0, 0xda50, 0x5d55, 0x56a0, 0xa6d0, 0x55d4, 0x52d0, 0xa9b8, 0xa950, 0xb4a0, 0xb6a6, 0xad50, 0x55a0, 0xaba4, 0xa5b0, 0x52b0, 0xb273, 0x6930, 0x7337, 0x6aa0, 0xad50, 0x4b55, 0x4b6f, 0xa570, 0x54e4, 0xd260, 0xe968, 0xd520, 0xdaa0, 0x6aa6, 0x56df, 0x4ae0, 0xa9d4, 0xa4d0, 0xd150, 0xf252, 0xd520);
		private var txtsolarMonth:Array = new Array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
		//定义私有函数干支等信息
		private var Gan:Array = new Array("甲", "乙", "丙", "丁", "戊", "己", "庚", "辛", "壬", "癸");
		private var Zhi:Array = new Array("子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥");
		private var Animals:Array = new Array("鼠", "牛", "虎", "兔", "龙", "蛇", "马", "羊", "猴", "鸡", "狗", "猪");
		//农历节气
		private var txtsolarTerm:Array = new Array("小寒", "大寒", "立春", "雨水", "惊蛰", "春分", "清明", "谷雨", "立夏", "小满", "芒种", "夏至", "小暑", "大暑", "立秋", "处暑", "白露", "秋分", "寒露", "霜降", "立冬", "小雪", "大雪", "冬至");
		private var txtsTermInfo:Array = new Array(0, 21208, 42467, 63836, 85337, 107014, 128867, 150921, 173149, 195551, 218072, 240693, 263343, 285989, 308563, 331033, 353350, 375494, 397447, 419210, 440795, 462224, 483532, 504758);
		private var nStr1:Array = new Array('日', '一', '二', '三', '四', '五', '六', '七', '八', '九', '十');
		private var nStr2:Array = new Array('初', '十', '廿', '卅', '□');
		private var monthName:Array = new Array("JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC");
		/*农历节日*/
		public static var lFtv:Array = new Array("0101*春节","0115 元宵节","0505 端午节","0707 七夕情人节","0715 中元节","0815 中秋节","0909 重阳节","1208 腊八节","1224 小年","0100*除夕");
		/*新历节日*/
		public static var sFtv:Array= new Array("0101*元旦","0214 情人节","05-2-7 母亲节","06-03-07 父亲节","0308 妇女节","0312 植树节","0315 消费者权益日","0401 愚人节","0501 劳动节","0504 青年节","0512 护士节","0601 儿童节","0701 建党节","0801 建军节","0808 父亲节","0910 教师节","1001*国庆节","1006 老人节","1024 联合国日","1225 圣诞节");
		private var cyear:int;
		private var cmonth:int;
		private var cday:int;
		private var isLeap:Boolean;
		private var nianzhu:String;
		private var yuezhu:String;
		private var rizhu:String;
		private var jie:String;
		private var my_newdate:Date;
		private var y:int, m:int, d:int;
		public function Lunar(_date:Date = null) {
			if (_date == null){
				setDate(new Date());
			}else{
				setDate(_date);
			}
		}
		public function setDate(value:Date):void {
			my_newdate = value;
			refresh();
		}
		
		private function refresh():void {
			var leap:int = 0;
			var temp:int = 0;

			y = my_newdate.getFullYear();
			m = my_newdate.getMonth();
			d = my_newdate.getDate();
			var offset:int = (Date.UTC(y, m, d)-Date.UTC(1900, 0, 31))/86400000;
			for (var i:int = 1900; i<2100 && offset>0; i++) {
				temp = lYearDays(i);
				offset -= temp;
			}
			if (offset<0) {
				offset += temp;
				i--;
			}
			cyear = i;
			leap = leapMonth(i);
			isLeap = false;
			for (var j:uint = 1; j<13 && offset>0; j++) {
				if (leap>0 && j == (leap+1) && isLeap == false) {
					--j;
					isLeap = true;
					temp = leapDays(cyear);
				} else {
					temp = monthDays(cyear, j);
				}
				if (isLeap == true && j == (leap+1)) {
					isLeap = false;
				}
				offset -= temp;
			}
			if (offset == 0 && leap>0 && j == leap+1) {
				if (isLeap) {
					isLeap = false;
				} else {
					isLeap = true;
					--j;
				}
			}
			if (offset<0) {
				offset += temp;
				--j;
			}
			cmonth = j;
			cday = offset+1;

			if (m<2) {
				nianzhu = cyclical(y-1900+36-1);
			} else {
				nianzhu = cyclical(y-1900+36);
			}
			yuezhu = cyclical((y-1900)*12+m+12);

			if (d == sTerm(y, m*2)) {
				jie = txtsolarTerm[m*2];
			} else {
				if (d == sTerm(y, m*2+1)) {
					jie = txtsolarTerm[m*2+1];
				} else {
					jie = "";
				}
			}
			this.jie = jie;
			leap=temp=i=offset=NaN
			//---------------------------------------------
			if (m == 1 && d>=sTerm(y, 2)) {
				nianzhu = cyclical(y-1900+36);
			}
			if ((d+1)>=sTerm(y, m*2)) {
				yuezhu = cyclical((y-1900)*12+m+13);
			}
			rizhu = cyclical(Date.UTC(y, m, 1, 0, 0, 0, 0)/86400000+25567+10+d-1);
		}
		public function get year():int {
			return cyear;
		}
		public function get month():int {
			return cmonth;
		}
		public function get date():int {
			return cday;
		}
		//获取大写农历月格式
		public function get monthStr():String {
			if (cmonth <= 10) return nStr1[cmonth];
			return nStr2[int(cmonth/10)]+nStr1[cmonth%10];
		}
		//获取大写农历日格式
		public function get dateStr():String {
			var _cday:uint=cday
			if (_cday == 1)_cday = 0;
			return nStr2[int(_cday/10)]+nStr1[_cday%10];
		}
		//获取当前年份
		public function get yearPro():String
		{
			return Animals[(y - 4) % 12];
		}
		//年柱
		public function get nianZhu():String {
			return nianzhu;
		}
		//月柱
		public function get yueZhu():String {
			return yuezhu;
		}
		//日柱
		public function get riZhu():String {
			return rizhu;
		}
		
		//节气
		public function get jieQi():String {
			return jie;
		}
		//时辰
		public function get shiceng():String {
			return Zhi[Math.round(my_newdate.getHours() % 23 / 2)] + "时";
		}
		//农历节日 
		public function get lunarFeast():String {
			var str:String=""
			for (var i:int;i<lFtv.length;i++ ) {
				if (month == int(lFtv[i].slice(0, 2)) && date== int(lFtv[i].slice(2, 4))) {
					str = lFtv[i].slice(4);
				}
			}
			var pattern:RegExp = /^\s*/;
			return str.replace(pattern,"");
		}
		//国历节日
		public function get solarFeast():String {
			var str:String = ""
			var len:uint = sFtv.length
			var jrAry:Array
			var runDate:Date = new Date(my_newdate);
			var runIndex:uint = 1;
			var addStr:String=""
			runDate.date = 1;
			for (var i:int; i < len; i++ ) {//2012-5-7 新增母亲节或父亲节这种周数定位的节日
				if ((my_newdate.month + 1) == int(sFtv[i].slice(0, 2))) {
					if (sFtv[i].indexOf("-") != -1) {//05-2-7 母亲节
						jrAry = String(sFtv[i].slice(0,sFtv[i].indexOf(" "))).split("-");
						if (int(jrAry[2]) == 7) jrAry[2] = 0;
						for (var j:uint = 1; j <= my_newdate.date; j++ ) {
							if (runDate.getDay() == int(jrAry[2])) {//对比星期数值
								if (runIndex == int(jrAry[1])) {//第几周
									if(runDate.date==my_newdate.date)
									addStr = sFtv[i].slice(sFtv[i].indexOf(" ") + 1);
									break;
									}else {
										runIndex++;
										}
								}
							runDate.date++
							}
						my_newdate.getDay()
						}
					if (my_newdate.date == int(sFtv[i].slice(2, 4))) {
						str = sFtv[i].slice(4);
					}
				}
			}
			len = NaN;
			if (str == "" && addStr == "") return "";
			return str.replace( /^\s*/,"")+" "+addStr;
		}
		private function lYearDays(y:int):int {
			var sum:int = 348;
			for (var i:uint = 0x8000; i>0x8; i >>= 1) {
				sum += (txtnum_info[y-1900] & i) ? 1 : 0;
			}
			return sum + leapDays(y);
		}
		private function leapDays(y:int):int {
			if (leapMonth(y)) {
				return txtnum_info[y - 1899] & 0xf == 0xf?30:29;
			} else {
				return 0;
			}
		}
		private function leapMonth(y:int):int {
			var lm:int = txtnum_info[y-1900] & 0xf;
			return lm == 0xf?0:lm;
		}
		private function monthDays(y:int, m:int):int {
			return txtnum_info[y - 1900] & 0x10000 >> m?30:29;
		}
		private function sTerm(y:int, n:int):int {
			var offDate:Date = new Date((31556925974.7*(y-1900)+txtsTermInfo[n]*60000)+Date.UTC(1900, 0, 6, 2, 5));
			return (offDate.getUTCDate());
		}
		private function solarDays(y:int, m:int):int {
			if (m == 1) {
				return y % 4 == 0 && y % 100 != 0 || y % 400 == 0?29:28;
			} else {
				return (txtsolarMonth[m]);
			}
		}
		private function cyclical(num:int):String {
			return Gan[num % 10] + Zhi[num % 12];
		}
	}
}